/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.mzk.manuscripts.tools.cli;

import cz.mzk.kramerius.fedoraaccess.FedoraConnector;
import cz.mzk.kramerius.fedoraaccess.FedoraServer;
import cz.mzk.kramerius.fedoraaccess.rest.RESTConnector;
import cz.mzk.manuscripts.tools.cli.imageLinks.PagePidUrlSuffixMapper;
import cz.mzk.manuscripts.tools.cli.imageLinks.PageUpdater;
import cz.mzk.rehan.commons.Dom4jUtils;
import cz.mzk.rehan.commons.PidList;
import cz.mzk.rehan.commons.PropertyLoader;
import cz.mzk.rehan.commons.Utils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.XPath;
import rukopisyimport.foxml.ImageIdentifier;
import rukopisyimport.foxml.images.ImageUrlBuilder;
import rukopisyimport.sourceData.BarCodeResolver;
import rukopisyimport.sourceData.ManuscriptIdentifier;

/**
 *
 * @author Martin Řehánek <rehan at mzk.cz>
 */
public class LinkToImageServerAction implements Action {

    private static final Logger logger = Logger.getLogger(LinkToImageServerAction.class.getName());
    private static final String PROP_SYSNO_BARCODE_MAPPING = "BarCodeResolver.mapping";
    private static final String DC_SIGNATURE_PREFIX = "signature:";
    private static final String BASE = "mzk03";
    private final XPath dcIdXpath = Dom4jUtils.createXPath("//dc:identifier");
    private final XPath foxmlHasPageXpath = Dom4jUtils.createXPath("//rdf:RDF/rdf:Description/kramerius:hasPage/@rdf:resource");
    private final XPath importLogSysnoXpath = Dom4jUtils.createXPath("/manuscript/sysno");
    private final File pidList;
    private final File teiDir;
    private final FedoraConnector con;
    private final BarCodeResolver barCodeResolver;
    private final PageUpdater updater;

    public LinkToImageServerAction(File properties, File pidList, File teiDir) throws Exception {
        this.pidList = pidList;
        this.teiDir = teiDir;
        this.con = new RESTConnector(new FedoraServer(properties));
        PropertyLoader loader = new PropertyLoader(properties);
        File mapping = loader.loadFile(PROP_SYSNO_BARCODE_MAPPING, true);
        barCodeResolver = new BarCodeResolver(mapping);
        updater = new PageUpdater(con, new ImageUrlBuilder(loader.getProperties()));
    }

    public void run() throws Exception {
        List<String> pids = (new PidList(pidList)).content();
        for (String pid : pids) {
            try {
                logger.log(Level.INFO, "updating document {0}", pid);
                Document foxml = con.getObjectFoxml(pid);
                String signature = getSingature(foxml);
                Document tei = getTeiDoc(signature);
                Document importLog = getImportLog(signature);
                ManuscriptIdentifier msId = getManuscriptId(importLog);
                PagePidUrlSuffixMapper mapper = new PagePidUrlSuffixMapper(importLog, tei);
                List<String> pagePidList = getPagePidList(foxml);
                for (String pagePid : pagePidList) {
                    ImageIdentifier imageId = getImageId(msId, pagePid, mapper);
                    updater.updatePage(pagePid, imageId);
                    Utils.busyWait(1);
                    //TODO:remove break
                    //break;
                }
            } catch (Throwable e) {
                logger.log(Level.SEVERE, "failed to update " + pid, e);
            }
        }
    }

    private Document getTeiDoc(String signature) throws FileNotFoundException, DocumentException {
        File teiFile = new File(teiDir.getAbsolutePath() + File.separator + signature + ".tei.xml");
        return Dom4jUtils.loadDocument(teiFile, false);
    }

    private String getSingature(Document foxml) throws Exception {
        List<Node> dcIdNodes = dcIdXpath.selectNodes(foxml);
        for (Node node : dcIdNodes) {
            String text = node.getText();
            if (text.startsWith(DC_SIGNATURE_PREFIX)) {
                return text.substring(DC_SIGNATURE_PREFIX.length());
            }
        }
        throw new Exception("cannot find signature");
    }

    private Document getImportLog(String signature) throws IOException, DocumentException {
        File logFile = new File(teiDir.getAbsolutePath() + File.separator + signature + ".log.xml");
        logger.log(Level.INFO, "import log: {0}", logFile.getAbsolutePath());
        return Dom4jUtils.loadDocument(logFile, false);
    }

    private List<String> getPagePidList(Document foxml) {
        List<Node> resourceNodes = foxmlHasPageXpath.selectNodes(foxml);
        List<String> result = new ArrayList<String>(resourceNodes.size());
        for (Node node : resourceNodes) {
            String unprefixed = node.getText();
            result.add(unprefixed.substring("info:fedora/".length()));
        }
        return result;
    }

    private ManuscriptIdentifier getManuscriptId(Document importLog) throws Exception {
        String sysno = findSysno(importLog);
        return ManuscriptIdentifier.instanceOf(BASE, sysno, barCodeResolver);
    }

    private String findSysno(Document importLog) throws Exception {
        Node node = importLogSysnoXpath.selectSingleNode(importLog);
        if (node == null) {
            throw new Exception("cannot find sysno in import log");
        }
        return node.getText();
    }

    private ImageIdentifier getImageId(ManuscriptIdentifier mnsId, String pagePid, PagePidUrlSuffixMapper mapper) throws Exception {
        String linkSuffix = mapper.getUrlSuffix(pagePid);
        return new ImageIdentifier(mnsId.getBase(), mnsId.getSysno(), mnsId.getBarcode(), linkSuffix);
    }
}
